﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace DotNetExtensions.AspNet.Net
{
    public class Network
    {
        public List<string> GetIPv4AddressList()
        {
            // IPv4正则表达式
            const string IPv4RegularExpression = "^(?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))$";

            // 注意：只获取已连接的网卡
            string NetworkAdapterQueryString = "SELECT * FROM Win32_NetworkAdapter WHERE (NetConnectionStatus = 2) AND (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))";

            //NetworkAdapterQueryString = "SELECT * FROM Win32_NetworkAdapter WHERE (NetConnectionStatus = 2) AND (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%')) AND (NOT (PNPDeviceID LIKE 'USB%'))";

            ManagementObjectCollection NetworkAdapterQueryCollection = new ManagementObjectSearcher(NetworkAdapterQueryString).Get();
            if (NetworkAdapterQueryCollection == null) return null;

            List<string> IPv4AddressList = new List<string>(NetworkAdapterQueryCollection.Count);
            foreach (ManagementObject mo in NetworkAdapterQueryCollection)
            {
                // 获取网卡配置信息
                string ConfigurationQueryString = "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index = " + mo["Index"];
                ManagementObjectCollection ConfigurationQueryCollection = new ManagementObjectSearcher(ConfigurationQueryString).Get();
                if (ConfigurationQueryCollection == null) continue;

                foreach (ManagementObject nacmo in ConfigurationQueryCollection)
                {
                    if ((bool)nacmo["IPEnabled"])
                    {
                        string[] IPCollection = nacmo["IPAddress"] as string[]; // IP地址
                        if (IPCollection != null)
                        {
                            foreach (string adress in IPCollection)
                            {
                                Match match = Regex.Match(adress, IPv4RegularExpression);
                                if (match.Success) { IPv4AddressList.Add(adress); break; }
                            }
                        }
                    }
                }
            }

            return IPv4AddressList;
        }

        public bool TryConnect(string hostname, int port)
        {
            TcpClient tcpClient = null;
            try
            {
                tcpClient = new TcpClient();
                tcpClient.ReceiveTimeout = 100;
                tcpClient.SendTimeout = 100;
                tcpClient.Connect(hostname, port);
                return tcpClient.Connected;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (tcpClient != null && tcpClient.Connected) tcpClient.Close();
            }
        }

        public bool Ping(string host)
        {
            Ping ping = null;
            PingReply reply = null;
            try
            {
                ping = new Ping();
                reply = ping.Send(host, 200);
                return reply.Status == IPStatus.Success;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (ping != null) ping.Dispose();
            }
        }

        public Task Listening(string hostname, int port, Action<bool> action, int timeout = 5000, CancellationToken token = default(CancellationToken))
        {
            return Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    if (token.IsCancellationRequested) break;
                    action?.Invoke(TryConnect(hostname, port));
                    Thread.Sleep(timeout);
                }
            }, token);
        }
        public Task Listening(string hostname, Action<bool> action, int timeout = 5000, CancellationToken token = default(CancellationToken))
        {
            return Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    if (token.IsCancellationRequested) break;
                    action?.Invoke(Ping(hostname));
                    Thread.Sleep(timeout);
                }
            }, token);
        }
    }
}
